/*
 * Copyright 2009 Eat Local Food, LLC
 * Copyright (c) 2007 osCommerce (this file was written after
 * code review of osCommerce).
 *
 * This file is part of gwtCommerce.
 *
 * gwtCommerce is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * gwtCommerce is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with gwtCommerce.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.elf.gwt.admin.client.components;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import com.elf.gwt.admin.client.AdminComponentController;
import com.elf.gwt.admin.client.subcomponents.AdminSubComponent;
import com.elf.gwt.admin.client.subcomponents.CategorySubComponent;
import com.elf.gwt.admin.client.subcomponents.ProductSubComponent;
import com.elf.gwt.common.client.access.RequestParameter;
import com.elf.gwt.common.client.callback.SubComponentCallback;
import com.elf.gwt.common.client.model.CategoryMetaModel;
import com.elf.gwt.common.client.model.CategoryModel;
import com.elf.gwt.common.client.model.DetailedProductModel;
import com.elf.gwt.common.client.subcomponent.CommonSubComponent;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HTMLTable;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.InlineHTML;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.Widget;

/**
 *
 */
public class CategoriesProductsComponent extends JSONServerComponent
{	
	protected CategoryMetaModel categoryMetaModel;
	protected HashMap<String, CategoryModel> categoriesHash;
	protected int selectedGroupId = 0;
	protected int previousCategoryId = 0;
	protected int selectedCategoryId = 0;
	protected int selectedChildCategoryId = 0;
	protected int selectedProductId = 0;

	protected HorizontalPanel bodyPanel;
	protected Grid leftPanel;
	protected Grid bottomPanel;
	protected HorizontalPanel buttonPanel = null;
	protected Button backButton;
	protected Button newCategoryButton;
	protected Button newProductButton;
	protected ListBox categoryListBox;
	protected Grid headerGrid = null;
	protected Grid parentGrid = null;

	protected Grid grid;
	protected AdminSubComponent subcomponent;
	protected String action = null;

	/**
	 * Constructor
	 */
	public CategoriesProductsComponent(AdminComponentController controller, String stylePrefix)
	{
		super(controller, stylePrefix);
		categoriesHash = new HashMap<String, CategoryModel>();
		setupTimer();
	}

	public void additionalRequestParameters()
	{
		if (action != null && action.length() > 0)
		{
			addRequestParameter(new RequestParameter ("action", action));
			if (action.equals("DeleteCategory") || action.equals("MoveCategory"))
			{
				addRequestParameter(new RequestParameter ("categoryId", selectedChildCategoryId));
			}
			if  (action.equals("DeleteProduct") || action.equals("MoveProduct") || action.equals("CopyProduct") || action.equals("NewProductLink") || action.equals("ToggleProductStatus"))
			{
				addRequestParameter(new RequestParameter ("productId", selectedProductId));
			}
			if  (action.equals("MoveProduct") || action.equals("CopyProduct") || action.equals("NewProductLink"))
			{
				addRequestParameter(new RequestParameter ("previousCategoryId", previousCategoryId));
			}
		}
		addRequestParameter(new RequestParameter ("selectedCategoryId", String.valueOf(selectedCategoryId)));
		action = null;
	}

	protected void buildMetaModel(JSONObject jsonObject) throws Exception
	{
		categoryMetaModel = new CategoryMetaModel(jsonObject);
	}

	protected void buildModel(JSONArray jsonArray) throws Exception
	{
		categoriesHash.clear();
		CategoryModel categoryModel = new CategoryModel();
		categoryModel.setName(categoryMetaModel.getStoreName());
		categoriesHash.put("0", categoryModel);

		super.buildModel(jsonArray);
		//Left Hand Tree Search to set count at upper levels.

		CategoryModel root = categoriesHash.get("0");
		calculateCount(root);
	}

	protected void buildModel(JSONObject jsonObject) throws Exception
	{
		CategoryModel model = new CategoryModel(jsonObject, categoryMetaModel);
		CategoryModel pmodel = getCategoryModel(model.getParentId());
		model.setParentModel(pmodel);
		categoriesHash.put(String.valueOf(model.getId()), model);

		if (pmodel != null)
		{
			List<CategoryModel> lst = pmodel.getChildList();
			boolean match = false;
			for (int j = 0; j< lst.size(); j++)
			{
				CategoryModel cmodel = lst.get(j);
				if (model.getId() == cmodel.getId())
				{
					match = true;
					break;
				}
			}
			if (!match && pmodel.getId() != model.getId())
			{
				pmodel.getChildList().add(model);
			}
		}	
	}

	protected int calculateCount(CategoryModel categoryModel)
	{
		List<CategoryModel> lst = categoryModel.getChildList();
		int count = 0;
		if (lst.size() > 0)
		{
			for (Iterator<CategoryModel>iter = lst.iterator(); iter.hasNext(); )
			{
				CategoryModel child = iter.next();
				count += calculateCount(child);
			}
			categoryModel.setCount(count);
		}
		return categoryModel.getCount();
	}

	public void buildFromModel() throws Exception
	{
		bodyPanel = new HorizontalPanel();

		CategoryModel selectedCategoryModel = categoriesHash.get(String.valueOf(selectedCategoryId));
		headerGrid = new Grid(1, 2);
		parentGrid = new Grid(1, 2);
		headerGrid.setWidget(0, 0, parentGrid);
		parentGrid.addClickHandler(backHandler);
		parentGrid.setWidget(0, 0, new Image(getImageDirectory() + "current_folder.gif"));
		parentGrid.getRowFormatter().addStyleName(0, "ComponentLink");
		parentGrid.setText(0, 1, selectedCategoryModel.getName());

		List<CategoryModel> childList = selectedCategoryModel.getChildList();
		List<DetailedProductModel> products = selectedCategoryModel.getProducts();
		int sz = childList.size();
		int sz1 = products.size();
		if (sz > 0 && selectedChildCategoryId == 0) selectedChildCategoryId = childList.get(0).getId();
		if (sz1 > 0 && selectedProductId == 0) selectedProductId = products.get(0).getId();
		grid = new Grid(sz+sz1+1, 5);
		grid.addClickHandler(childTableHandler);
		grid.setText(0, 1, "Categories / Products");
		grid.setText(0, 2, "Status");
		grid.setText(0, 3, "Sort Order");
		grid.setText(0, 4, "Action");
		CategoryModel selectedChildCategoryModel = null;
		for (int i = 0; i < sz; i++)
		{
			int row = i+1;
			grid.getRowFormatter().addStyleName(row, "ComponentLink");
			grid.setWidget(row, 0, new Image(getImageDirectory() + "folder.gif"));
			int k = row % 2;
			String rowStyle = "Even";
			if (k > 0) rowStyle = "Odd";
			grid.getRowFormatter().addStyleName(row, rowStyle);
			CategoryModel categoryModel = childList.get(i);
			grid.setText(row, 1, categoryModel.getName());
			grid.setText(row, 3, String.valueOf(categoryModel.getSortOrder()));

			if (selectedChildCategoryId == categoryModel.getId()) {
				selectedChildCategoryModel = categoryModel;
				grid.setWidget(row, 4, new Image(getImageCommonDirectory() + "icon_arrow_right.gif"));
				grid.getRowFormatter().addStyleName(row, "Selected");
			}
			else {
				grid.setWidget(row, 4, new Image(getImageCommonDirectory() + "icon_info.gif"));
				grid.getRowFormatter().removeStyleName(row, "Selected");
			}
		}

		DetailedProductModel selectedProductModel = null;
		for (int i = 0; i < sz1; i++)
		{
			int row = i+sz+1;
			grid.getRowFormatter().addStyleName(row, "ComponentLink");
			grid.setWidget(row, 0, new Image(getImageDirectory() + "preview.gif"));
			int k = row % 2;
			String rowStyle = "Even";
			if (k > 0) rowStyle = "Odd";
			grid.getRowFormatter().addStyleName(row, rowStyle);
			DetailedProductModel productModel = products.get(i);
			grid.setText(row, 1, productModel.getName());

			Grid statusGrid = new Grid(1, 3);

			if (productModel.isStatus())
			{

				statusGrid.setWidget(0, 0, new Image(getImageCommonDirectory() + "icon_status_green.gif"));
				statusGrid.setWidget(0, 1, new InlineHTML("&nbsp;"));
				Image offImage = new Image(getImageCommonDirectory() + "icon_status_red_off.gif");
				offImage.addStyleName("ComponentLink");
				offImage.addStyleName("index:"+row);
				offImage.addClickHandler(statusClickHandler);
				statusGrid.setWidget(0, 2, offImage);
			}
			else
			{
				Image offImage = new Image(getImageCommonDirectory() + "icon_status_green_off.gif");
				offImage.addStyleName("ComponentLink");
				offImage.addStyleName("index:"+row);
				offImage.addClickHandler(statusClickHandler);
				statusGrid.setWidget(0, 0, offImage);
				statusGrid.setWidget(0, 1, new InlineHTML("&nbsp;"));
				statusGrid.setWidget(0, 2, new Image(getImageCommonDirectory() + "icon_status_red.gif"));
			}
			grid.setWidget(row, 2, statusGrid);

			if (selectedProductId == productModel.getId()) {
				selectedProductModel = productModel;
				grid.setWidget(row, 4, new Image(getImageCommonDirectory() + "icon_arrow_right.gif"));
				grid.getRowFormatter().addStyleName(row, "Selected");
			}
			else {
				grid.setWidget(row, 4, new Image(getImageCommonDirectory() + "icon_info.gif"));
				grid.getRowFormatter().removeStyleName(row, "Selected");
			}
		}

		leftPanel = new Grid(2, 1);
		bodyPanel.add(leftPanel);
		leftPanel.setWidget(0, 0, grid);
		bottomPanel = new Grid(1, 2);
		leftPanel.setWidget(1, 0, bottomPanel);
		bottomPanel.setHTML(0, 0, "Categories: " + childList.size() + "<br/>Products: " + selectedCategoryModel.getProducts().size());

		if (buttonPanel == null)
		{
			buttonPanel = new HorizontalPanel();

			backButton = new Button("back", backHandler);
			backButton.addStyleName("ComponentLink");
			buttonPanel.add(backButton);
			buttonPanel.add(new InlineHTML("&nbsp;&nbsp;"));

			newCategoryButton = new Button("new category", newCategoryHandler);
			newCategoryButton.addStyleName("ComponentLink");
			buttonPanel.add(newCategoryButton);
			buttonPanel.add(new InlineHTML("&nbsp;&nbsp;"));

			newProductButton = new Button("new product", newProductHandler);
			newProductButton.addStyleName("ComponentLink");
			buttonPanel.add(newProductButton);
			buttonPanel.add(new InlineHTML("&nbsp;&nbsp;"));

			categoryListBox = new ListBox();
			categoryListBox.addChangeHandler(new ChangeHandler() {
				public void onChange(ChangeEvent event) {
					int index = categoryListBox.getSelectedIndex();
					String value = categoryListBox.getValue(index);
					if (value != null)
					{
						selectedCategoryId = Integer.parseInt(value);
						selectedChildCategoryId = 0;
						action = null;
						String history = getHandle() + "--" + selectedGroupId + "--" + selectedCategoryId + "--" + selectedChildCategoryId;
						onSelection(history);
					}
				}
			});
			categoryListBox.addItem("--Go To Category--","-1");
			buildCategoryListBox(categoryListBox, getCategoryModel(0), "");

		}
		backButton.setVisible(selectedCategoryId > 0);
		newCategoryButton.setVisible(sz1 == 0);
		newProductButton.setVisible(sz == 0);
		bottomPanel.setWidget(0, 1, buttonPanel);
		categoryListBox.setSelectedIndex(0);
		headerGrid.setWidget(0, 1, categoryListBox);

		if (sz > 0 && selectedChildCategoryModel != null)
		{
			subcomponent = new CategorySubComponent(thisComponent,
					selectedChildCategoryModel, adminController, getHandle(), subComponentCallback);
			subcomponent.build();
			bodyPanel.add(subcomponent);
		}
		if (sz1 > 0 && selectedProductModel != null)
		{
			subcomponent = new ProductSubComponent(thisComponent,
					selectedProductModel, adminController, getHandle(), subComponentCallback);
			subcomponent.build();
			bodyPanel.add(subcomponent);
		}

		clear();
		add(headerGrid);
		add(bodyPanel);


		onBuilt();
	}

	protected ClickHandler statusClickHandler = new ClickHandler() {
		public void onClick(ClickEvent event) {
			Widget source = (Widget)event.getSource();
			String stylenames = source.getStyleName();
			int loc = stylenames.indexOf("index:");
			stylenames = stylenames.substring(loc+6);
			loc = stylenames.indexOf(" ");
			if (loc > -1) stylenames = stylenames.substring(0, loc);
			int rowIndex = Integer.parseInt(stylenames);
			CategoryModel selectedCategoryModel = categoriesHash.get(String.valueOf(selectedCategoryId));
			List<DetailedProductModel> products = selectedCategoryModel.getProducts();
			DetailedProductModel productModel = products.get(rowIndex -1);
			selectedProductId = productModel.getId();
			action = "ToggleProductStatus";
			build(true);
		}
	};

	protected ClickHandler newCategoryHandler= new ClickHandler() {
		public void onClick(ClickEvent event)
		{
			CategoryModel selectedCategoryModel = categoriesHash.get(String.valueOf(selectedCategoryId));
			List<CategoryModel> childList = selectedCategoryModel.getChildList();
			int sz = childList.size();
			selectedChildCategoryId = 0;
			for (int i = 0; i < sz; i++)
			{
				grid.setWidget(i+1, 4, new Image(getImageCommonDirectory() + "icon_info.gif"));
				grid.getRowFormatter().removeStyleName(i+1, "Selected");
			}
			bodyPanel.remove(subcomponent);
			CategoryModel categoryModel = new CategoryModel();
			categoryModel.setCategoryMetaModel(categoryMetaModel);
			categoryModel.setParentId(selectedCategoryId);
			categoryModel.setParentModel(selectedCategoryModel);
			categoryModel.setName("");
			CategorySubComponent categorySubcomponent = new CategorySubComponent(thisComponent,
					categoryModel, adminController, getHandle(), subComponentCallback);
			categorySubcomponent.setEdit(true);
			categorySubcomponent.build();
			bodyPanel.add(categorySubcomponent);
			if (focusWidget != null) {
				focusWidget.setFocus(true);
			}
		}
	};

	protected ClickHandler newProductHandler= new ClickHandler() {
		public void onClick(ClickEvent event)
		{
			String history = "EditProductComponent--" + selectedGroupId + "--" + selectedCategoryId + "--0";
			onSelection(history);
		}
	};

	protected ClickHandler backHandler = new ClickHandler() {
		public void onClick(ClickEvent event)
		{
			CategoryModel selectedCategoryModel = categoriesHash.get(String.valueOf(selectedCategoryId));
			selectedChildCategoryId = selectedCategoryId;
			selectedCategoryId = selectedCategoryModel.getParentId();
			action = null;
			String history = getHandle() + "--" + selectedGroupId + "--" + selectedCategoryId + "--" + selectedChildCategoryId;
			onSelection(history);
		}
	};

	protected ClickHandler childTableHandler= new ClickHandler() {
		public void onClick(ClickEvent event)
		{
			HTMLTable.Cell cell = grid.getCellForEvent(event);
			int rowIndex = cell.getRowIndex();

			if (rowIndex > 0)
			{
				CategoryModel selectedCategoryModel = categoriesHash.get(String.valueOf(selectedCategoryId));
				List<CategoryModel> childList = selectedCategoryModel.getChildList();
				List<DetailedProductModel> products = selectedCategoryModel.getProducts();

				int sz = childList.size();
				int sz1 = products.size();

				if (sz > 0)
				{
					CategoryModel categoryModel = childList.get(rowIndex -1);
					int colIndex = cell.getCellIndex();
					if (colIndex == 0)
					{
						selectedCategoryId = categoryModel.getId();
						selectedChildCategoryId = 0;
						action = null;
						String history = getHandle() + "--" + selectedGroupId + "--" + selectedCategoryId + "--" + selectedChildCategoryId;
						onSelection(history);
					}
					else
					{
						selectedChildCategoryId = categoryModel.getId();
						for (int i = 0; i < sz; i++)
						{
							CategoryModel childCategoryModel = childList.get(i);
							if (categoryModel == childCategoryModel) {
								grid.setWidget(i+1, 4, new Image(getImageCommonDirectory() + "icon_arrow_right.gif"));
								grid.getRowFormatter().addStyleName(i+1, "Selected");
							}
							else {
								grid.setWidget(i+1, 4, new Image(getImageCommonDirectory() + "icon_info.gif"));
								grid.getRowFormatter().removeStyleName(i+1, "Selected");
							}
						}
						bodyPanel.remove(subcomponent);
						if (categoryModel != null)
						{
							subcomponent = new CategorySubComponent(thisComponent,
									categoryModel, adminController, getHandle(), subComponentCallback);
							subcomponent.build();
							bodyPanel.add(subcomponent);
						}
					}
				}
				else if (sz1 > 0)
				{
					DetailedProductModel productModel = products.get(rowIndex -1);
					int colIndex = cell.getCellIndex();
					if (colIndex == 0)
					{
						action = null;
						String history = getHandle()  + "--" + selectedGroupId + "--" + selectedCategoryId + "--0--" + productModel.getId();
						onSelection(history);
					}
					else
					{
						for (int i = 0; i < sz1; i++)
						{
							DetailedProductModel childProductModel = products.get(i);
							if (productModel == childProductModel) {
								grid.setWidget(i+1, 4, new Image(getImageCommonDirectory() + "icon_arrow_right.gif"));
								grid.getRowFormatter().addStyleName(i+1, "Selected");
							}
							else {
								grid.setWidget(i+1, 4, new Image(getImageCommonDirectory() + "icon_info.gif"));
								grid.getRowFormatter().removeStyleName(i+1, "Selected");
							}
						}
						bodyPanel.remove(subcomponent);
						if (productModel != null)
						{
							subcomponent = new ProductSubComponent(thisComponent,
									productModel, adminController, getHandle(), subComponentCallback);
							subcomponent.build();
							bodyPanel.add(subcomponent);
							selectedProductId = productModel.getId();
						}
					}
				}
			}
		}
	};

	protected SubComponentCallback subComponentCallback = 
		new SubComponentCallback() {

		public void onNavigate(CommonSubComponent subComponent) {
			action = subComponent.getSuperAction();
			String history = action + "Component--" + selectedGroupId + "--" + selectedCategoryId + "--" + selectedProductId;
			onSelection(history);
		}

		public void onSuccess(CommonSubComponent subComponent) {
			if (subComponent.getSuperAction() != null)
				action = subComponent.getSuperAction();
			build(true);
		}

		public void onError(CommonSubComponent subComponent, Throwable exception) {}
	};

	public CategoryModel getCategoryModel(int id) {
		return categoriesHash.get(String.valueOf(id));
	}

	public boolean updateFromHistoryParameters(String[] params)
	{
		adminController.getMultipleResultsComponent().addComponent(this);
		selectedCategoryId = 0;
		selectedChildCategoryId = 0;
		selectedProductId = 0;
		try {
			selectedGroupId = Integer.parseInt(params[1]);
			CatalogGroupComponent catalogGroupComponent = (CatalogGroupComponent) controller.getComponent("CatalogGroupComponent");
			catalogGroupComponent.setSelectedGroupModel(selectedGroupId);	
			catalogGroupComponent.setSelectedInGUI();
			adminController.getNavigationStackPanel().showStack(catalogGroupComponent.getIndex());

			selectedCategoryId = Integer.parseInt(params[2]);
			selectedChildCategoryId = Integer.parseInt(params[3]);
			selectedProductId = Integer.parseInt(params[4]);
		}
		catch (Exception e) {}

		setVisible(true);
		return super.updateFromHistoryParameters(params);
	}

	public int getSelectedCategoryId() {
		return selectedCategoryId;
	}

	public void setSelectedCategoryId(int selectedCategoryId) {
		this.previousCategoryId = this.selectedCategoryId;
		this.selectedCategoryId = selectedCategoryId;
	}

	public int getSelectedChildCategoryId() {
		return selectedChildCategoryId;
	}

	public void setSelectedChildCategoryId(int selectedCategoryId) {
		this.selectedChildCategoryId = selectedCategoryId;
	}

	public static void buildCategoryListBox(ListBox listBox, CategoryModel cmodel, String prefix)
	{		
		listBox.addItem(prefix + cmodel.getName(),String.valueOf(cmodel.getId()));
		List<CategoryModel> children = cmodel.getChildList();
		Iterator<CategoryModel> iter = children.iterator();
		while(iter.hasNext())
		{
			CategoryModel child = iter.next();
			buildCategoryListBox(listBox, child, prefix + "+");
		}
	}
}
